package com.hf.wujian.model.imp;

import com.hf.wujian.constant.ResultEnum;
import com.hf.wujian.model.GameHall;
import com.hf.wujian.model.GameRoom;
import com.hf.wujian.model.GameUser;
import io.netty.channel.ChannelHandlerContext;

import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * 游戏大厅实现类
 *
 * @author hf
 * @date 2018/11/23
 * @version 1.0
 *
 */
public class BSHGameHall implements GameHall{

    /**
     * 大厅内所有房间
     */
    private Map<String,GameRoom> gameRooms;
    /**
     * 大厅内所有用户
     */
    private Map<String,GameUser> gameUsers;

    private static ReadWriteLock userRwlock = new ReentrantReadWriteLock(true);//用户读写锁
    private static ReadWriteLock roomRwlock = new ReentrantReadWriteLock(true);//房间读写锁

    public BSHGameHall(){
        gameRooms = new HashMap<>();
        gameUsers = new HashMap<>();
    }

    /**
     * 创建游戏房间方法
     * @param uuid 游戏用户uuid
     * @param gameRoomName 房间名
     * @param ctx 客户端通道
     */
    @Override
    public void createGameRoom(String uuid,String gameRoomName,ChannelHandlerContext ctx) {
        ResultEnum result = ResultEnum.SUCCESS;
        userRwlock.readLock().lock();
        roomRwlock.writeLock().lock();
        try {
            GameUser gameUser = gameUsers.get(uuid);
            //用户为空返回请先登录
            if (gameUser == null) {
                result = ResultEnum.PLEASE_LOGIN;
                return;
            }

            //已经有所属房间
            if (gameUser.getGameRoom() != null) {
                result = ResultEnum.HAVING_ROOM;
                return;
            }

            //房间名重复
            if (gameRooms.get(gameRoomName) != null) {
                result = ResultEnum.ROOMNAME_REPETITION;
                return;
            }

            //创建房间
            GameRoom gameRoom = new BSHGameRoom(gameRoomName, gameUser);
            gameRooms.put(gameRoomName,gameRoom);
        } catch (Exception e) {
            e.printStackTrace();
            result = ResultEnum.HAVING_ROOM;
        } finally {
            roomRwlock.writeLock().unlock();
            userRwlock.readLock().unlock();
            returnMsg(result, ctx);
        }
    }

    /**
     * 销毁游戏房间方法
     * @param gameRoomName 房间名
     */
    @Override
    public void destroyGameRoom(String gameRoomName,GameUser gameUser,ChannelHandlerContext ctx) {
        ResultEnum result = ResultEnum.SUCCESS;
        roomRwlock.writeLock().lock();
        try {
            GameRoom gameRoom = gameRooms.remove(gameRoomName);

            if(gameRoom == null){
                result = ResultEnum.ROOM_DOES_NOT_EXIST;
            }else{
                gameRoom.destroyRoom(gameUser);
            }
        }finally {
            roomRwlock.writeLock().unlock();
            returnMsg(result, ctx);
        }
    }

    /**
     * 加入大厅方法
     * @param gameUser 游戏用户
     * @param ctx 客户端通道
     */
    @Override
    public void addGameUser(GameUser gameUser,ChannelHandlerContext ctx) {
        ResultEnum returnCode = ResultEnum.SUCCESS;
        userRwlock.writeLock().lock();
        try {
            //判断此用户是否存在，若用户已经存在则直接返回
            if(userIsExist(gameUser.getUuid())){
                returnCode = ResultEnum.USER_ALREADY_EXISTS;
                throw new Exception("用户已经存在");
            }
            //添加用户
            gameUsers.put(gameUser.getUuid(),gameUser);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            userRwlock.writeLock().unlock();
        }
        returnMsg(returnCode,ctx);
    }

    /**
     * 退出大厅方法
     * @param gameUser 游戏用户
     * @param ctx 客户端通道
     */
    @Override
    public void removeGameUser(GameUser gameUser,ChannelHandlerContext ctx) {
        ResultEnum returnCode = ResultEnum.SUCCESS;
        userRwlock.writeLock().lock();
        try {
            //判断是否此用户是否存在，不存在则直接返回
            if (!userIsExist(gameUser.getUuid())) {
                returnCode = ResultEnum.WITHOUT_THIS_USER;
                throw new Exception("用户不存在");
            }
            GameRoom gameRoom = gameUser.getGameRoom();
            if(gameRoom != null){
                gameRoom.removeGameUser(gameUser);
            }

            //移除用户
            gameUsers.remove(gameUser.getUuid());


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            userRwlock.writeLock().unlock();
        }
        returnMsg(returnCode,ctx);
    }

    /**
     * 根据uuid获得用户
     * @param uuid 游戏用户uuid
     * @return 游戏用户
     */
    @Override
    public GameUser getGameUser(String uuid) {
        userRwlock.readLock().lock();
        GameUser gameUser;
        try{
            gameUser = gameUsers.get(uuid);
        }finally {
            userRwlock.readLock().unlock();
        }
        return gameUser;
    }

    /**
     * 获得游戏房间名列表
     * @return 游戏房间名列表
     */
    @Override
    public List<String> getGameRooms() {
        List<String> result;
        userRwlock.readLock().lock();
        try{
            result = new ArrayList<>(gameRooms.keySet());
        }finally {
            userRwlock.readLock().unlock();
        }
        return result;
    }

    /**
     * 根据房间名获得房间
     * @param gameRoom 房间名
     * @return 房间
     */
    @Override
    public GameRoom getGameRoom(String gameRoom) {
        GameRoom result;
        userRwlock.readLock().lock();
        try{
            result = gameRooms.get(gameRoom);
        }finally {
            userRwlock.readLock().unlock();
        }
        return result;
    }

    /**
     * 获取大厅用户总数
     * @return 大厅用户总数
     */
    @Override
    public int getGameUserSize() {
        int count = 0;
        userRwlock.readLock().lock();
        try{
            count = gameUsers.size();
        }finally {
            userRwlock.readLock().unlock();
        }
        return count;
    }

    /**
     * 获取大厅房间总数
     * @return 大厅房间总数
     */
    @Override
    public int getGameRoomSize() {
        int count = 0;
        userRwlock.readLock().lock();
        try{
            count = gameRooms.size();
        }finally {
            userRwlock.readLock().unlock();
        }
        return count;
    }

    /**
     * 根据uuid判断用户是否存在
     * 只能在userRwlock锁内调用，否则会线程不安全
     * @param uuid 用户uuid
     * @return 用户是否存在
     */
    public boolean userIsExist(String uuid) {
        boolean result = true;
        if(uuid == null || uuid.equals("")){
            result = false;
        }

        if (gameUsers.get(uuid) == null) {
            result = false;
        }
        return result;
    }

    /**
     *
     * @param resultEnum 返回值
     * @param ctx 客户端通道
     */
    @Override
    public void returnMsg(ResultEnum resultEnum,ChannelHandlerContext ctx) {
        ctx.writeAndFlush(resultEnum.result + "\r\n");
    }
}
